﻿//#include "pch.h"
#include "MyFFPlayer.h"

extern "C" {
#include <libavfilter/avfilter.h>
#include <libavutil/avstring.h>

#include <SDL.h>
}

/**
* Custom SDL_Event type.
* Notifies the next video frame has to be displayed.
*/
#define FF_REFRESH_EVENT (SDL_USEREVENT)

/**
* Custom SDL_Event type.
* Notifies the program needs to quit.
*/
#define FF_QUIT_EVENT (SDL_USEREVENT + 1)


bool MyFFPlayer04::b_s_net_comp_initialized = false;
bool MyFFPlayer04::b_s_sdl_initialized = false;


MyFFPlayer04::MyFFPlayer04()
{
    memset(&mediaState, 0, sizeof(mediaState));

}


MyFFPlayer04::~MyFFPlayer04()
{
}


int MyFFPlayer04::Init(EnumInitType type, int log_level = AV_LOG_INFO, std::string* errorMsg = nullptr)
{
    int retval = -1;
    bool bInitNetComp = (type & EIT_UseNetComponent);
    bool bUseSDL = (type & EIT_UseSDL);

    do
    {
#if 0
        // 其实已经废弃了，不知道从哪个版本开始的
        av_register_all();
#if FF_API_NEXT
        avfilter_register_all();
#endif
#endif

        av_log_set_level(log_level);

        if (bUseSDL) {
            Uint32 flags = 0;
            if (EIT_Init_Video & type) flags |= SDL_INIT_VIDEO;
            if (EIT_Init_Audio & type) flags |= SDL_INIT_AUDIO;
            if (EIT_Init_Timer & type) flags |= SDL_INIT_TIMER;
            retval = SDL_Init(flags);
            if (retval < 0) {
                printf("Could not initialize SDL - %s\n.", SDL_GetError());

                char buf[128];
                const char* pErr1 = SDL_GetErrorMsg(buf, 128);
                if (errorMsg) {
                    *errorMsg = buf;
                }
                break;
            }
            b_s_sdl_initialized = true;
        }
        
        if (bInitNetComp) {
            // [2021-01-18] 这个也快要去掉了
            avformat_network_init();
            b_s_net_comp_initialized = true;
        }
        
        
    } while (false);

    if (retval < 0) {
        uninit();
    }
    return 0;
}


int MyFFPlayer04::uninit()
{
    if (b_s_net_comp_initialized) {
        avformat_network_deinit();
        b_s_net_comp_initialized = false;
    }

    if (b_s_sdl_initialized) {
        SDL_Quit();
        b_s_sdl_initialized = false;
    }

    return 0;
}

int MyFFPlayer04::get_error_message(int code, std::string & msg)
{
    std::string str_err_msg;
    str_err_msg.reserve(256);
    int ret = av_strerror(code, (char*)str_err_msg.data(), str_err_msg.length());
    msg = str_err_msg.c_str();
    return ret;
}

void MyFFPlayer04::video_refresh_timer(void * userdata)
{
    
}

void MyFFPlayer04::schedule_refresh(VideoState * videoState, int delay)
{
    SDL_TimerID time_id = SDL_AddTimer(delay, sdl_refresh_timer_cb, videoState);
    printf("SDL_AddTimer returns [TimerID = %6d]", time_id);
}

int MyFFPlayer04::decode_thread(void * arg)
{
    // 未完成
    return 0;
}

Uint32 MyFFPlayer04::sdl_refresh_timer_cb(Uint32 interval, void * opaque)
{
#if 1
    // create SDL_Event of type FF_REFRESH_EVENT
    SDL_Event event;
    event.type = FF_REFRESH_EVENT;
    event.user.data1 = opaque;

    // push the event to the events queue
    SDL_PushEvent(&event);

    // return 0 to stop the timer
#endif
    return 0;
}

int MyFFPlayer04::open(const std::string& path)
{
    int retval = -1;
    
    
    do
    {
        av_strlcpy(mediaState.filename, path.c_str(), sizeof(mediaState.filename));

        mediaState.pictq_mutex = SDL_CreateMutex();
        mediaState.pictq_cond = SDL_CreateCond();

#if 0
        schedule_refresh(&mediaState, 39);
#else
        mediaState.timerID = SDL_AddTimer(39, sdl_refresh_timer_cb, &mediaState);
        if (!mediaState.timerID) {
            printf("SDL_AddTimer return failed - exiting.\n");
            break;
        }
#endif

        mediaState.decode_tid = SDL_CreateThread(decode_thread, "Decoding Thread", &mediaState);
        if (!mediaState.decode_tid) {
            // 内部线程创建失败
            printf("Could not start decoding SDL_Thread - exiting.\n");
            // av_free(pMediaState); // 如果是用av_mallocz分配的内存的话
            break;
        }

        // infinite loop waiting for fired events
        SDL_Event event;
        for (;;)
        {
            SDL_WaitEvent(&event);
            switch (event.type)
            {
            case FF_QUIT_EVENT:
            case SDL_QUIT:
            {
                mediaState.quit = 1;
                SDL_Quit();
            }
            break;

            case FF_REFRESH_EVENT:
            {
                //video_refresh_timer(event.user.data1);
            }
            break;

            default:
            {
                // nothing to do
            }
            break;
            }

            // check global quit flag
            if (mediaState.quit)
            {
                // exit for loop
                break;
            }
        }



        retval = 0;
    } while (false);
    
    if (retval != 0) {
        this->close();
    }

    return retval;
}

void MyFFPlayer04::close()
{
    //
    if (mediaState.pictq_cond) {
        SDL_DestroyCond(mediaState.pictq_cond);
        mediaState.pictq_cond = nullptr;
    }

    if (mediaState.timerID) {
        SDL_RemoveTimer(mediaState.timerID);
        mediaState.timerID = 0;
    }

    if (mediaState.pictq_mutex) {
        SDL_DestroyMutex(mediaState.pictq_mutex);
        mediaState.pictq_mutex = nullptr;
    }
}
